package eu.codlab.game.gameba.activities;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.content.pm.ActivityInfo;
import android.graphics.Canvas;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.Toast;
import eu.codlab.androidemu.services.BluetoothServerService;
import eu.codlab.androidemu.services.BluetoothState;
import eu.codlab.androidemu.services.BluetoothStateHelper;
import eu.codlab.androidemu.services.CommandListener;
import eu.codlab.androidemu.utilities.ReportHelper;
import eu.codlab.game.gameba.Emulator;
import eu.codlab.game.gameba.EmulatorView;
import eu.codlab.game.gameba.EmulatorViewControl;
import eu.codlab.game.gameba.VirtualKeypadView;
import eu.codlab.game.gameba.nonem.input.GameKeyListener;
import eu.codlab.game.gameba.nonem.input.Keyboard;
import eu.codlab.game.gameba.nonem.input.Trackball;
import eu.codlab.game.gameba.VirtualKeypad;
import eu.codlab.src.game.R;

public class GameBoidManagerBack implements GameKeyListener,
DialogInterface.OnCancelListener, CommandListener, OnSharedPreferenceChangeListener {
	private boolean _isServerBluetooth;
	private GameBoidManagerBack(Activity activity, boolean isServerBluetooth){
		_activity = activity;
		_isServerBluetooth = isServerBluetooth;
	}

	public static GameBoidManagerBack getInstance(Activity activity){
		return new GameBoidManagerBack(activity, false);
	}
	public static GameBoidManagerBack getInstance(Activity activity,boolean isServerBluetooth){
		return new GameBoidManagerBack(activity, isServerBluetooth);
	}

	private Activity _activity;

	private static final int REQUEST_SETTINGS = 3;

	private static final int DIALOG_QUIT_GAME = 1;
	private static final int DIALOG_LOAD_STATE = 2;
	private static final int DIALOG_SAVE_STATE = 3;

	private static final int GAMEPAD_LEFT_RIGHT =
			(Emulator.GAMEPAD_LEFT | Emulator.GAMEPAD_RIGHT);
	private static final int GAMEPAD_UP_DOWN =
			(Emulator.GAMEPAD_UP | Emulator.GAMEPAD_DOWN);
	private static final int GAMEPAD_DIRECTION =
			(GAMEPAD_UP_DOWN | GAMEPAD_LEFT_RIGHT);

	private static Emulator emulator;
	private static int resumeRequested;
	private static Thread emuThread;

	private EmulatorView emulatorView;
	private EmulatorViewControl emulatorView2;
	private Keyboard keyboard;
	private VirtualKeypad keypad;
	private Trackball trackball;

	private String currentGame;
	private String lastPickedGame;
	private boolean isMenuShowing;
	private int quickLoadKey;
	private int quickSaveKey;
	private SharedPreferences settings;
	public SharedPreferences getPreferences(int type){
		return _activity.getSharedPreferences("eu.codlab.src.game_preferences", type);
	}

	public void onCreate(Bundle savedInstanceState){
		if(Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2){
			_activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
			_activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
		}

		File datadir = _activity.getDir("data", Activity.MODE_PRIVATE);
		emulator = null;//Emulator.createInstance(_activity,"gba");


		// load settings 1
		settings = getPreferences(Activity.MODE_PRIVATE);
		settings.registerOnSharedPreferenceChangeListener(this);

		if(_isServerBluetooth || (_activity.getIntent() != null &&
				(_activity.getIntent().getBooleanExtra("console", false) == true ||
				(_activity.getIntent().getExtras()!= null && _activity.getIntent().getExtras().getBoolean("console") == true)))){

			final Intent i = new Intent(_activity, BluetoothServerService.class);
			_activity.startService(i);

			_activity.setContentView(R.layout.gba_main_console);
			BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
			if(adapter == null || adapter.isEnabled() == false){
				showErrorBluetooth();
			}


			Thread t = new Thread(){
				public void run(){
					while(BluetoothServerService.getInstance() == null){
						try {
							Thread.sleep(1000);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					BluetoothServerService.getInstance().setCommandListener(GameBoidManagerBack.this);
				}
			};
			t.start();
		}else{
			Log.d("SETTGINGS", ""+settings.getBoolean("stretchcontrol",true));
			if(settings.getBoolean("stretchcontrol",true) == true)
				_activity.setContentView(R.layout.gba_main);
			else
				_activity.setContentView(R.layout.gba_main_between_controls);
		}

		//keypad.setGameKeyListener(this);
		//keypad.resize(-1,-1);
		FrameLayout frame = (FrameLayout)_activity.findViewById(R.id.frame);
		frame.invalidate();
		emulatorView = (EmulatorView)_activity.findViewById(R.id.emulator);
		emulatorView2 = (EmulatorViewControl)_activity.findViewById(R.id.keypad);
		if(emulatorView2 == null)
			keypad = new VirtualKeypad(this._activity);
		else
			keypad = emulatorView2.getVirtualKeypad();
		//VirtualKeypadView keypadview = (VirtualKeypadView)_activity.findViewById(R.id.keypad);
		emulatorView.setEmulator(emulator);
		//}
		emulatorView2.invalidate();
		emulatorView2.requestFocus();
		keypad.setGameKeyListener(emulatorView2, this);

		switchToView(R.id.empty);

		// create physical keyboard and trackball
		keyboard = new Keyboard(emulatorView2, this);
		trackball = new Trackball(keyboard, this);

		// create virtual keypad
		// copy preset files
		copyAsset(new File(datadir, "game_config.txt"));
		copyAsset(new File(datadir, "g.bin"));

		// load settings2
		lastPickedGame = settings.getString("lastPickedGame", null);
		loadGlobalSettings();

		resetBios(datadir);

		// restore state if any
		if (savedInstanceState != null){
			currentGame = savedInstanceState.getString("currentGame");
			switchToView(currentGame == null ? R.id.empty : R.id.game);
		}else{
			String path = getROMFilePath();
			Log.d("loading",path);
			if(path.endsWith(".gba") || path.endsWith(".bin") || path.endsWith(".zip")){
				lastPickedGame = path;
				loadROM(path);
			}else if(path.endsWith(".bin")){
				loadBIOS(path);
			}

			// load BIOS
			if (loadBIOS(settings.getString("bios", null))) {
				// restore last running game
				String last = settings.getString("lastGame", null);
				if (last != null) {
					saveLastRunningGame(null);
					if (new File(getGameStateFile(last, 0)).exists() &&
							loadROM(last, false))
						quickLoad();
				}
			}
		}
	}


	private void resetBios(File datadir){
		Log.d("loading bios",""+loadBIOS(new File(datadir, "g.bin").getAbsolutePath()));
	}

	private void resetBios(){
		File datadir = _activity.getDir("data", Activity.MODE_PRIVATE);
		resetBios(datadir);
	}

	private String getROMFilePath() {
		return _activity.getSharedPreferences("files", 0).getString("file", "NoLocalFile");
	}

	protected void onDestroy() {
		if (_activity.isFinishing()) {
			resumeRequested = 0;
			if(emulator != null)
				emulator.cleanUp();
			emulator = null;
		}
	}

	protected void onPause() {
		pauseEmulator();
	}

	protected void onResume() {
		loadGlobalSettings();
		resumeEmulator();
	}

	protected void onStop() {
		SharedPreferences.Editor editor = this.getPreferences(Activity.MODE_PRIVATE).edit();
		editor.putString("lastPickedGame", lastPickedGame);
		editor.commit();
	}

	protected void onSaveInstanceState(Bundle outState) {
		outState.putString("currentGame", currentGame);
	}

	protected void onRestoreInstanceState(Bundle savedInstanceState){

	}

	public void onStart(){
		//TODO fix this bug
		EmulatorViewControl emulatorView2 = (EmulatorViewControl)_activity.findViewById(R.id.keypad);
		if(emulatorView2 != null)
			emulatorView2.reDraw();
	}
	protected Dialog onCreateDialog(int id) {
		switch (id) {
		case DIALOG_LOAD_STATE:
			return createLoadStateDialog();
		case DIALOG_SAVE_STATE:
			return createSaveStateDialog();
		case DIALOG_QUIT_GAME:
			return createQuitGameDialog();
		default:
			return null;
		}
	}

	protected void onPrepareDialog(int id, Dialog dialog) {
		switch (id) {
		case DIALOG_QUIT_GAME:
		case DIALOG_LOAD_STATE:
		case DIALOG_SAVE_STATE:
			pauseEmulator();
			break;
		}
	}

	public boolean onKeyDown(int keyCode, KeyEvent event) {
		if (keyCode == quickLoadKey) {
			quickLoad();
			return true;
		}
		if (keyCode == quickSaveKey) {
			quickSave();
			return true;
		}
		if (keyCode == KeyEvent.KEYCODE_BACK && currentGame != null) {
			_activity.showDialog(DIALOG_QUIT_GAME);
			return true;
		}
		return false;
	}

	public boolean onCreateOptionsMenu(Menu menu) {
		_activity.getMenuInflater().inflate(R.menu.gba_main, menu);
		if(_activity.getRequestedOrientation() == ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE)
			menu.findItem(R.id.menu_block_screen).setChecked(true);
		return true;
	}

	public void onOptionsMenuClosed(Menu menu) {
		if (isMenuShowing) {
			isMenuShowing = false;
			resumeEmulator();
		}
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		if (isMenuShowing) {
			isMenuShowing = false;
			resumeEmulator();
		}

		switch (item.getItemId()) {
		case R.id.menu_block_screen:
			if(item != null){
				item.setChecked(!item.isChecked());
			}
			if(item.isChecked()){
				_activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
			}else{
				_activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR);
			}
			return true;

		case R.id.menu_settings:
			_activity.startActivityForResult(
					new Intent(_activity, GamePreferences.class), REQUEST_SETTINGS);
			return true;

		case R.id.menu_reset:
			emulator.reset();
			return true;

		case R.id.menu_save_state:
			_activity.showDialog(DIALOG_SAVE_STATE);
			return true;

		case R.id.menu_load_state:
			_activity.showDialog(DIALOG_LOAD_STATE);
			return true;

		case R.id.menu_close:
			unloadROM();
			return true;
		case R.id.menu_quit:
			_activity.finish();
			return true;
		}
		return false;
	}

	@Override
	public void onGameKeyChanged() {
		int states = 0;
		states |= keyboard.getKeyStates();
		states |= keypad.getKeyStates();

		if ((states & GAMEPAD_DIRECTION) != 0)
			trackball.reset();
		else
			states |= trackball.getKeyStates();

		// resolve conflict keys
		if ((states & GAMEPAD_LEFT_RIGHT) == GAMEPAD_LEFT_RIGHT)
			states &= ~GAMEPAD_LEFT_RIGHT;
		if ((states & GAMEPAD_UP_DOWN) == GAMEPAD_UP_DOWN)
			states &= ~GAMEPAD_UP_DOWN;

		emulator.setKeyStates(states);
	}

	@Override
	public void onCancel(DialogInterface dialog) {
		resumeEmulator();
	}

	private void resumeEmulator() {
		if (resumeRequested++ == 0) {
			keyboard.reset();
			keypad.reset();
			trackball.reset();
			onGameKeyChanged();

			emulator.resume();
		}
		emulator.resume();
	}

	private void pauseEmulator() {
		if (--resumeRequested == 0)
			emulator.pause();
	}

	private boolean copyAsset(File file) {
		if (file.exists())
			return true;

		InputStream in = null;
		OutputStream out = null;

		try {
			in = _activity.getAssets().open(file.getName());
			out = new FileOutputStream(file);

			byte[] buf = new byte[8192];
			int len;
			while ((len = in.read(buf)) > 0)
				out.write(buf, 0, len);

		} catch (Exception e) {
			e.printStackTrace();
			return false;

		} finally {
			try {
				if (out != null)
					out.close();
				if (in != null)
					in.close();
			} catch (IOException e) {
			}
		}
		return true;
	}

	private static int getScalingMode(String mode) {
		if (mode.equals("original"))
			return EmulatorView.SCALING_ORIGINAL;
		if (mode.equals("proportional"))
			return EmulatorView.SCALING_PROPORTIONAL;
		return EmulatorView.SCALING_STRETCH;
	}

	private void saveLastRunningGame(String game) {
		SharedPreferences.Editor editor = this.getPreferences(Activity.MODE_PRIVATE).edit();
		editor.putString("lastGame", game);
		editor.commit();
	}

	private void loadGlobalSettings() {
		pauseEmulator();

		SharedPreferences settings =
				PreferenceManager.getDefaultSharedPreferences(_activity);
		emulator.setOption("autoFrameSkip",
				settings.getBoolean("autoFrameSkip", true));
		emulator.setOption("maxFrameSkips",
				Integer.toString(settings.getInt("maxFrameSkips", 2)));
		emulator.setOption("soundEnabled", 
				settings.getBoolean("soundEnabled", true));

		trackball.setEnabled(settings.getBoolean("enableTrackball", false));
		/*keypad.setVisibility(settings.getBoolean("enableVirtualKeypad",
				GamePreferences.getDefaultVirtualKeypadEnabled(_activity)) ?
						View.VISIBLE : View.GONE);*/

		emulatorView.setScalingMode(getScalingMode(
				settings.getString("scalingMode", "proportional")));

		// key bindings
		final int[] gameKeys = GamePreferences.gameKeys;
		final String[] prefKeys = GamePreferences.keyPrefKeys;
		final int[] defaultKeys = GamePreferences.getDefaultKeys(_activity);

		keyboard.clearKeyMap();
		for (int i = 0; i < prefKeys.length; i++) {
			keyboard.mapKey(gameKeys[i],
					settings.getInt(prefKeys[i], defaultKeys[i]));
		}

		// shortcut keys
		quickLoadKey = settings.getInt("quickLoad", 0);
		quickSaveKey = settings.getInt("quickSave", 0);

		resumeEmulator();
	}

	private void switchToView(int id) {
		final int viewIds[] = {
				R.id.empty,
				R.id.game
		};
		for (int i = 0; i < viewIds.length; i++) {
			if(_activity.findViewById(viewIds[i]) != null)
				_activity.findViewById(viewIds[i]).setVisibility(
						viewIds[i] == id ? View.VISIBLE : View.INVISIBLE);
		}
	}

	private Dialog createLoadStateDialog() {
		DialogInterface.OnClickListener l =
				new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				loadGameState(which);
				resumeEmulator();
			}
		};

		return new AlertDialog.Builder(_activity).
				setTitle(R.string.gba_load_state_title).
				setItems(R.array.gba_game_state_slots, l).
				setOnCancelListener(this).create();
	}

	private Dialog createSaveStateDialog() {
		DialogInterface.OnClickListener l =
				new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				saveGameState(which);
				resumeEmulator();
			}
		};

		return new AlertDialog.Builder(_activity).
				setTitle(R.string.gba_save_state_title).
				setItems(R.array.gba_game_state_slots, l).
				setOnCancelListener(this).create();
	}

	private Dialog createQuitGameDialog() {
		DialogInterface.OnClickListener l =
				new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				switch (which) {
				/*case 0:
					resumeEmulator();
					onLoadROM();
					break;*/
				case 1:
					quickSave();
					saveLastRunningGame(currentGame);
					// fall through
				case 2:
					_activity.finish();
					break;
				}
			}
		};

		return new AlertDialog.Builder(_activity).
				setTitle(R.string.gba_quit_game_title).
				setItems(R.array.gba_exit_game_options, l).
				setOnCancelListener(this).create();
	}


	String biosFileName = "";
	private boolean loadBIOS(String name) {
		biosFileName = name;
		Log.d("begin loadBios", ""+name);
		if (name != null && emulator.loadBIOS(name)) {

			SharedPreferences.Editor editor =settings.edit();
			editor.putString("bios", biosFileName);
			editor.commit();
			return true;
		}

		return false;
	}

	private boolean loadROM(String fname) {
		return loadROM(fname, true);
	}

	String romFileName = "";
	private boolean loadROM(final String fname, boolean failPrompt) {
		unloadROM();
		romFileName = fname;
		Log.d("load rom",fname);
		if (!emulator.loadROM(fname)) {
			Toast.makeText(_activity, R.string.gba_load_rom_failed,
					Toast.LENGTH_SHORT).show();
			Toast.makeText(_activity, "Loading : "+romFileName,
					Toast.LENGTH_SHORT).show();
			DialogInterface.OnClickListener l =
					new DialogInterface.OnClickListener() {
				@Override
				public void onClick(DialogInterface dialog, int which) {
					switch (which) {
					case DialogInterface.BUTTON_POSITIVE:
						sendReport(1);
						break;
					case DialogInterface.BUTTON_NEGATIVE:
						_activity.finish();
						break;
					}
				}
			};

			new AlertDialog.Builder(_activity).
			setCancelable(false).
			setTitle(R.string.gba_load_failed).
			setMessage(R.string.gba_load_rom_failed).
			setPositiveButton(R.string.gba_load_failed_send, l).
			setNegativeButton(R.string.gba_quit, l).
			show();



			return false;
		}
		currentGame = fname;
		switchToView(R.id.game);
		return true;
	}

	private void sendReport(int type){
		ReportHelper.sendReport(_activity, type, _activity.getClass(), getROMFilePath(),0);
	}
	private void unloadROM() {
		Log.d("unload","rom");
		if (currentGame != null) {
			emulator.unloadROM();
			currentGame = null;
			switchToView(R.id.empty);
		}
	}

	private void saveGameState(int slot) {
		String fname = getGameStateFile(currentGame, slot);
		emulator.saveState(fname);
	}

	private void loadGameState(int slot) {
		String fname = getGameStateFile(currentGame, slot);
		if (new File(fname).exists())
			emulator.loadState(fname);
	}

	private void quickSave() {
		saveGameState(0);
	}

	private void quickLoad() {
		loadGameState(0);
	}

	private static String getGameStateFile(String name, int slot) {
		int i = name.lastIndexOf('.');
		if (i >= 0)
			name = name.substring(0, i);
		name += ".ss" + slot;
		return name;
	}


	@Override
	public void showErrorBluetooth() {

		DialogInterface.OnClickListener l =
				new DialogInterface.OnClickListener() {
			@Override
			public void onClick(DialogInterface dialog, int which) {
				switch (which) {
				case DialogInterface.BUTTON_POSITIVE:
					break;
				}
			}
		};

		new AlertDialog.Builder(_activity).
		setCancelable(false).
		setTitle(R.string.gba_console_bluetooth_error_title).
		setMessage(R.string.gba_console_bluetooth_error_message).
		setPositiveButton(R.string.gba_quit, l).
		show();
	}

	@Override
	public void onCommand(int command, int state) {
		keypad.onKeyFromClient(null, command, state);
	}


	@Override
	public void onBluetoothState(final BluetoothState state) {
		_activity.runOnUiThread(new Thread(){
			public void run(){
				Toast.makeText(_activity, BluetoothStateHelper.getResourceFromBluetoothStateServer(state), Toast.LENGTH_LONG).show();
			}
		});
	}

	@Override
	public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
			String key) {
		loadGlobalSettings();
	}

	/*@Override
	public boolean onTouch(View v, MotionEvent event) {
		if (keypad != null)
			return keypad.onTouch(event, false);

		return false;
	}*/

}
